<template>
  <div id="main">
    <!-- 锚点 -->
    <div class="card">
      <el-button type="primary" size="medium"><a href="#3Dpie">3D 饼图</a></el-button>
      <el-button type="primary" size="medium"><a href="#bar">柱状图</a></el-button>
    </div>
    <!-- ------------------------------------------------------ -->
    <el-divider id="3Dpie"></el-divider>
    <el-card class="box-card">
      <div slot="header">3D 饼图</div>
      <div ref="pie" class="echarts"></div>
    </el-card>
  </div>
</template>

<script>
export default {
  data() {
    return {
      dataList: [
        { name: '京东', value: 400, itemStyle: { color: '#B79149', opacity: 1 } },
        { name: '淘宝', value: 500, itemStyle: { color: '#027AC2', opacity: 1 } },
        { name: '天猫', value: 600, itemStyle: { color: '#0ABDC6', opacity: 1 } },
      ]
    }
  },
  mounted() {
    this.get3DPie()  // 3D 饼图

  },
  methods: {
    // 饼图  -------------------  效果
    get3DPie() {
      var echarts = require('echarts');
      var myChart = echarts.init(this.$refs.pie);
      // ------------------------------------------------------
      // 生成扇形的曲面的高度
      function getHeight3D(series, height) {
        series.sort((a, b) => {
          return b.pieData.value - a.pieData.value
        })
        return (height * 35) / series[0].pieData.value
      }
      // 生成扇形的曲面参数方程
      function getParametricEquation(startRatio, endRatio, isSelected, isHovered, k, h) {
        // startRatio - 每个扇区的开始角度 | endRatio - 每个扇区的结束角度 | k - 辅助参数 | h - 高度
        const midRatio = (startRatio + endRatio) / 2;
        const startRadian = startRatio * Math.PI * 2;
        const endRadian = endRatio * Math.PI * 2;
        const midRadian = midRatio * Math.PI * 2;
        // 如果只有一个扇形，则不实现选中效果。
        if (startRatio === 0 && endRatio === 1) { isSelected = false; }
        // 通过扇形内径/外径的值，换算出辅助参数 k（默认值 1/3）
        k = typeof k !== 'undefined' ? k : 1 / 3;
        // 计算选中效果分别在 x 轴、y 轴方向上的位移（未选中，则位移均为 0）
        const offsetX = isSelected ? Math.cos(midRadian) * 0.1 : 0;
        const offsetY = isSelected ? Math.sin(midRadian) * 0.1 : 0;
        // 计算高亮效果的放大比例（未高亮，则比例为 1）
        const hoverRate = isHovered ? 1.05 : 1;
        // 返回曲面参数方程
        return {
          u: { min: -Math.PI, max: Math.PI * 3, step: Math.PI / 32, },
          v: { min: 0, max: Math.PI * 2, step: Math.PI / 20, },
          x(u, v) {
            if (u < startRadian) { return offsetX + Math.cos(startRadian) * (1 + Math.cos(v) * k) * hoverRate; }
            if (u > endRadian) { return offsetX + Math.cos(endRadian) * (1 + Math.cos(v) * k) * hoverRate; }
            return offsetX + Math.cos(u) * (1 + Math.cos(v) * k) * hoverRate;
          },
          y(u, v) {
            if (u < startRadian) { return offsetY + Math.sin(startRadian) * (1 + Math.cos(v) * k) * hoverRate; }
            if (u > endRadian) { return offsetY + Math.sin(endRadian) * (1 + Math.cos(v) * k) * hoverRate; }
            return offsetY + Math.sin(u) * (1 + Math.cos(v) * k) * hoverRate;
          },
          z(u, v) {
            if (u < -Math.PI * 0.5) { return Math.sin(u); }
            if (u > Math.PI * 2.5) { return Math.sin(u) * h * 0.1; }
            // 当前图形的高度是Z根据h（每个value的值决定的）
            return Math.sin(v) > 0 ? 1 * h * 0.1 : -1;
          },
        };
      }
      // 生成模拟 3D 饼图的配置项
      function getPie3D(pieData, internalDiameterRatio) {
        const series = [];
        // 总和
        let sumValue = 0; // 计算 pieData 总和
        let startValue = 0; // 每个扇区的开始角度
        let endValue = 0; // 每个扇区的结束角度
        const k = typeof internalDiameterRatio !== 'undefined' ? (1 - internalDiameterRatio) / (1 + internalDiameterRatio) : 1 / 3;

        // 为每一个饼图数据，生成一个 series-surface 配置
        for (let i = 0; i < pieData.length; i += 1) {
          sumValue += pieData[i].value; // 计算 pieData 总和
          const seriesItem = {
            name: typeof pieData[i].name === 'undefined' ? `series${i}` : pieData[i].name, // 系列名称, 用于 tooltip 的显示, legend 的图例筛选
            type: 'surface',
            parametric: true, // 是否为参数曲面
            wireframe: { show: false, }, // 曲面图的网格线
            pieData: pieData[i],
            pieStatus: { selected: false, hovered: false, k: k, },
            // center: ['10%', '10%']
          }
          if (typeof pieData[i].itemStyle !== 'undefined') {
            const { itemStyle } = pieData[i]
            typeof pieData[i].itemStyle.color !== 'undefined' ? (itemStyle.color = pieData[i].itemStyle.color) : null // 图形的颜色
            typeof pieData[i].itemStyle.opacity !== 'undefined' ? (itemStyle.opacity = pieData[i].itemStyle.opacity) : null // 图形的不透明度
            seriesItem.itemStyle = itemStyle;
          }
          series.push(seriesItem);
        }
        // 使用上一次遍历时，计算出的数据和 sumValue，调用 getParametricEquation 函数，
        // 向每个 series-surface 传入不同的参数方程 series-surface.parametricEquation，也就是实现每一个扇形。
        const legendData = []
        for (let i = 0; i < series.length; i += 1) {
          endValue = startValue + series[i].pieData.value;
          series[i].label = { show: true, position: 'outside', }
          series[i].pieData.startRatio = startValue / sumValue;
          series[i].pieData.endRatio = endValue / sumValue;
          series[i].parametricEquation = getParametricEquation(
            series[i].pieData.startRatio,
            series[i].pieData.endRatio,
            false,
            false,
            k,
            // 我这里做了一个处理，使除了第一个之外的值都是10
            // series[i].pieData.value === series[0].pieData.value ? 20 : 40,
            series[i].pieData.value
          );
          startValue = endValue;
          legendData.push(series[i].name);
        }
        let boxHeight = getHeight3D(series, 15)
        // 准备待返回的配置项，把准备好的 legendData、series 传入。
        const option = {
          legend: {
            data: legendData,
            orient: 'vertical',
            left: '10%', // 图例组件离容器上侧的距离 20  '20%'  left  center  right
            top: 'center', // 图例组件离容器上侧的距离 20  '20%'  top  middle  bottom
            itemGap: 40, // 图例每项之间的间隔。横向布局时为水平间隔，纵向布局时为纵向间隔
            itemWidth: 40, // 图例标记的图形宽度
            itemHeight: 20, // 图例标记的图形高度
            textStyle: { color: '#222', fontSize: 16, },
            selectedMode: true, // 图例选择的模式，控制是否可以通过点击图例改变系列的显示状态
            formatter: function (params) {
              for (let i = 0; i < pieData.length; i++) {
                if (pieData[i].name == params) {
                  return params + ' ' + pieData[i].value + ' ' + '占比' + ' ' + (pieData[i].value / sumValue * 100).toFixed(2) + '%'
                }
              }
            }
          },
          tooltip: {
            formatter: (params) => {
              if (params.seriesName !== 'mouseoutSeries') {
                return `${params.seriesName}<br/>
                <span style="display:inline-block;margin-right:5px;border-radius:10px;width:10px;height:10px;background-color:${params.color};"></span>
                ${option.series[params.seriesIndex].pieData.value}`
              }
              return '';
            },
          },
          xAxis3D: { min: -1, max: 1, },
          yAxis3D: { min: -1, max: 1, },
          zAxis3D: { min: -1, max: 1, },
          grid3D: {
            show: false, // 是否显示三维笛卡尔坐标系
            boxHeight: boxHeight, // 三维笛卡尔坐标系在三维场景中的高度
            top: '0%', // 组件的视图离容器上侧的距离
            left: '10%', // 组件的视图离容器上侧的距离
            viewControl: { // 用于鼠标的旋转，缩放等视角控制
              alpha: 30, // 视角绕 x 轴,即上下旋转的角度
              beta: 80, // 视角绕 y 轴,即左右旋转的角度
              rotateSensitivity: 1, // 旋转操作的灵敏度, 值越大越灵敏, 默认为 1, 设置为 0 后无法旋转
              zoomSensitivity: 0, // 缩放操作的灵敏度, 值越大越灵敏, 默认为 1, 设置为 0 后无法缩放
              panSensitivity: 0, // 平移操作的灵敏度, 值越大越灵敏, 默认为 1, 设置为 0 后无法平移
              autoRotate: true, // 是否开启视角绕物体的自动旋转查看
              distance: 200, // 默认视角距离主体的距离
            },
            postEffect: { // 后处理特效可以为画面添加高光、景深、环境光遮蔽（SSAO）、调色等效果。可以让整个画面更富有质感
              enable: false, // 是否开启后处理特效。默认关闭
              bloom: { // 高光特效。高光特效用来表现很 "亮" 的颜色
                enable: false, // 是否开启光晕特效
                bloomIntensity: 0.1, // 光晕的强度，默认为 0.1
              },
              SSAO: {
                enable: true, // 是否开启环境光遮蔽。默认不开启
                quality: 'high', // 环境光遮蔽的质量, 'low' | 'medium' | 'high' | 'ultra'
                radius: 20, // 环境光遮蔽的采样半径。半径越大效果越自然
              },
            },
          },
          series,
        }
        return option;
      }
      var option = getPie3D(this.dataList, 0.6);
      myChart.setOption(option);
    },

    // get3DPie() {
    //   var echarts = require('echarts');
    //   var myChart = echarts.init(this.$refs.pie);
    //   let dataList = this.dataList
    //   let nums = []
    //   dataList.forEach(function (item) { nums.push(item.value) })
    //   let total = nums.reduce((prev, cur) => { return prev + cur })
    //   dataList.forEach(function (item) {
    //     item.zb = parseInt((item.value / total) * 100);
    //     item.h = item.zb * 1.5 >= 70 ? 70 : item.zb * 1.5
    //   })
    //   console.log('-----', dataList)
    //   var option = {}
    //   myChart.setOption(option);
    // },
  }

}
</script>

<style scoped>
.box-card {
  width: 85%;
  margin-bottom: 20px;
  border: 1px solid red;
}
.card {
  width: 10%;
  height: 75%;
  background: #eee;
  display: flex;
  flex-direction: column;
  justify-content: space-around;
  align-items: center;
  border: 1px solid #888;
  position: fixed;
  top: 150px;
  right: 50px;
  z-index: 10;
}

.echarts {
  width: 90%;
  height: 350px;
  border: 1px solid black;
  margin: 10px auto 20px;
  /* background: #090F41; */
  z-index: 10;
}
.echarts-box {
  width: 90%;
  height: 350px;
  border: 1px solid black;
  margin: 10px auto 20px;
  /* position: absolute; */
}
</style>